<script setup>
import { computed, ref } from 'vue'
import {
  checkAlgorithm,
  createAlgorithm,
  deleteAlgorithm,
  getAlgorithmInfo,
  startAlgorithm,
  stopAlgorithm,
  updateAlgorithm
} from '@/api/algorithm/algorithm'
import { Message, Modal } from '@arco-design/web-vue'
import { cloneDeep } from 'lodash'
import dayjs from 'dayjs'
const pagination = ref({
  pageNum: 1,
  pageSize: 10,
  total: 0
})
const visible = ref(false)

const columns = [
  {
    title: '序号',
    slotName: 'index',
    width: 60
  },
  {
    title: '算法名称',
    dataIndex: 'algorithmName',
    tooltip: { position: 'left' },
    ellipsis: true,
    width: 150
  },
  {
    title: '算法类型',
    dataIndex: 'algorithmType',
    render: ({ record }) => {
      const match = algorithmTypeEnum.find((item) => item.code === record.algorithmType)
      return match ? match.label : '--'
    },
    width: 110
  },
  {
    title: '算法描述',
    dataIndex: 'algorithmDesc',
    tooltip: { position: 'bottom' },
    ellipsis: true
  },
  {
    title: '创建时间',
    dataIndex: 'createTime',
    render: ({ record }) => {
      return dayjs(record.startTime).format('YYYY-MM-DD HH:mm:ss')
    },
    width: 175
  },
  {
    title: '操作',
    slotName: 'action',
    width: 310
  }
]
const scroll = {
  x: '100%',
  maxHeight: '700px'
}
const tableLoading = ref(false)
const algorithmPageData = ref([])

const dialogTitle = computed(() => {
  switch (dialogType.value) {
    case 'add':
      return '添加算法'
    case 'edit':
      return '修改算法信息'
    default:
      return ''
  }
})

const descData = ref([
  {
    label: '算法名称',
    code: 'algorithmName',
    value: ''
  },
  {
    label: '算法code',
    code: 'algorithmCode',
    value: ''
  },
  {
    label: '算法类型',
    code: 'algorithmType',
    value: ''
  },
  {
    label: '算法文件',
    code: 'algorithmFileName',
    value: ''
  },
  {
    label: '算法启动服务文件名',
    code: 'startServiceFile',
    value: ''
  },
  {
    label: '算法描述',
    code: 'algorithmDesc',
    value: ''
  }
])

const dialogType = ref('add')

const algorithmTypeEnum = [
  {
    code: 1,
    label: '剔野'
  },
  {
    code: 2,
    label: '填充'
  },
  {
    code: 3,
    label: '平滑'
  },
  {
    code: 5,
    label: '趋势预测'
  }
]

const algorithmFormRef = ref()

const DEFAULT_ALGORITHM_FORM = {
  id: '', // 主键
  algorithmName: '', // 算法名称
  startServiceFile: '', // 算法服务启动文件名
  algorithmCode: '', // 算法code
  algorithmType: '', // 算法类型(1:剔野,2:填充,3:平滑,4:事后诊断,5:趋势预测)
  algorithmDesc: '', // 算法描述
  algorithmFile: '', // 算法脚本文件
  algorithmFileName: '', // 算法脚本文件名称
  // serverState: true, //服务状态(0 停止,1 运行)
  // algorithmState: true, //算法状态(0 停止,1 运行)
  createTime: '', // 创建时间
  algorithmPath: '', // 算法文件存储路径
  algorithmParams: [], // 开始结束参数
  isBuiltInAlgorithms: 0,
  trialAddr: '', // 模型训练地址
  predictAddr: '' // 模型调用地址
}

const algorithmForm = ref(cloneDeep(DEFAULT_ALGORITHM_FORM))
const handleAdd = () => {
  dialogType.value = 'add'
  visible.value = true
}

function toFormData(obj) {
  const formData = new FormData()

  for (const key in obj) {
    const value = obj[key]
    if (value === undefined || value === null) continue
    if (Array.isArray(value)) {
      value.forEach((item, index) => {
        formData.append(`${key}[${index}]`, item)
      })
    } else if (key === 'algorithmFile' && value instanceof File) {
      formData.append('algorithmFile', value, value.name)
    } else {
      formData.append(key, value)
    }
  }

  return formData
}

const handleSubmit = async () => {
  const API = dialogType.value === 'add' ? createAlgorithm : updateAlgorithm
  if (!algorithmFormRef.value) return false
  const res = await algorithmFormRef.value.validate()
  if (res !== undefined) return false

  try {
    await algorithmFormRef.value.validate()
    const formData = toFormData(algorithmForm.value)
    const { code, data, message } = await API(formData)

    if (code === 200) {
      Message.success(data || message)
      await loadList()
      return true
    } else {
      Message.error(data || message)
      return false
    }
  } catch (errors) {
    console.log('校验失败:', errors)
    return false
  }
}

const resetForm = () => {
  if (algorithmFormRef.value) {
    algorithmFormRef.value.clearValidate()
    algorithmForm.value = cloneDeep(DEFAULT_ALGORITHM_FORM)
  }
  file.value = []
}
const handleBeforeClose = () => {
  resetForm()
}

const file = ref([])

const clearFile = () => {
  file.value = []
  algorithmForm.value.algorithmFileName = ''
  algorithmForm.value.algorithmFile = undefined
}

const beforeRemove = () => {
  clearFile()
  return true
}
const handleUpload = (options) => {
  const { fileItem, onSuccess, onError } = options
  algorithmForm.value.algorithmFileName = fileItem.file.name
  algorithmForm.value.algorithmFile = fileItem.file
  onSuccess()
}

const loadList = async () => {
  try {
    tableLoading.value = true
    const { code, data } = await getAlgorithmInfo({
      pageStart: pagination.value.pageNum,
      pageLength: pagination.value.pageSize,
      startTime: '',
      endTime: ''
    })
    if (code === 200) {
      tableLoading.value = false
      algorithmPageData.value = data.list
      pagination.value.total = Number(data.total)
    }
  } catch (e) {
    console.log(e)
  } finally {
    tableLoading.value = false
  }
}
loadList()

const handlePageChange = (page) => {
  pagination.value.pageNum = page
  loadList()
}

const handlePageSizeChange = (size) => {
  pagination.value.pageSize = size
  loadList()
}

const detailVisible = ref(false)
const getAlgorithmTypeLabel = (code) => {
  const match = algorithmTypeEnum.find((item) => item.code === code)
  return match ? match.label : '--'
}
const handleDetail = async (record) => {
  try {
    tableLoading.value = true
    const { code, data, message } = await checkAlgorithm(record.id)
    if (code === 200) {
      descData.value.forEach((item) => {
        if (item.code === 'algorithmType') {
          item.value = getAlgorithmTypeLabel(data.algorithmType)
        } else {
          item.value = data[item.code] ?? ''
        }
      })
      tableLoading.value = false
      detailVisible.value = true
    } else {
      Message.error(message)
    }
  } catch (e) {
    console.log(e)
  } finally {
    tableLoading.value = false
  }
}
const handleEdit = async (record) => {
  try {
    tableLoading.value = true
    dialogType.value = 'edit'
    const { code, data, message } = await checkAlgorithm(record.id)
    if (code === 200) {
      algorithmForm.value = { ...data }
      visible.value = true
      file.value = [
        {
          name: data.algorithmFileName,
          algorithmPath: data.algorithmPath
        }
      ]
      tableLoading.value = false
    } else {
      Message.error(message)
    }
  } catch (e) {
    console.log(e)
  } finally {
    tableLoading.value = false
  }
}
const handleDelete = (record) => {
  Modal.confirm({
    title: '提示',
    content: `确定要删除【${record.algorithmName}】这个算法吗？`,
    okText: '确认',
    cancelText: '取消',
    onOk: async () => {
      try {
        const { code, message } = await deleteAlgorithm(record.id)
        if (code === 200) {
          Message.success('删除成功')
        } else {
          Message.error(message || '删除失败')
        }
      } catch (e) {
        console.log(e)
      } finally {
        await loadList()
      }
    }
  })
}
const handleStartOrStop = async (val, record) => {
  try {
    tableLoading.value = true
    if (val) {
      const { code, data, message } = await startAlgorithm(record)
      if (code === 200) {
        Message.success(data || message)
      } else {
        Message.error(data || message)
      }
    } else {
      const { code, data, message } = await stopAlgorithm(record)
      if (code === 200) {
        Message.success(data || message)
      } else {
        Message.error(data || message)
      }
    }
  } catch (e) {
    console.log(e)
  } finally {
    await loadList()
  }
}
</script>

<template>
  <div class="page-algorithm-management">
    <div class="table-card">
      <div class="table-card-header">
        <div class="table-card-header-right">
          <a-button type="primary" @click="handleAdd">
            <template #icon><icon-plus /></template>新建</a-button
          >
        </div>
      </div>
      <a-table
        :columns="columns"
        :data="algorithmPageData"
        :pagination="false"
        :scroll="scroll"
        :scrollbar="false"
        :loading="tableLoading"
      >
        <template #index="{ rowIndex }">
          {{ rowIndex + 1 }}
        </template>
        <template #action="{ record }">
          <a-button status="success" size="mini" type="text" @click="handleDetail(record)">
            <template #icon>
              <icon-file />
            </template>
            详情
          </a-button>
          <a-button size="mini" type="text" @click="handleEdit(record)">
            <template #icon>
              <IconEdit />
            </template>
            修改
          </a-button>

          <a-button status="danger" size="mini" type="text" @click="handleDelete(record)">
            <template #icon>
              <IconDelete />
            </template>
            删除
          </a-button>
          <a-switch type="round" v-model="record.serverState" @change="(val) => handleStartOrStop(val, record)">
            <template #checked>启动服务</template>
            <template #unchecked>停止服务</template>
          </a-switch>
        </template>
      </a-table>
      <div class="table-card-footer">
        <a-pagination
          :total="pagination.total"
          :current="pagination.page"
          :page-size="pagination.pageSize"
          show-total
          show-jumper
          show-page-size
          @change="handlePageChange"
          @page-size-change="handlePageSizeChange"
        />
      </div>
    </div>
    <a-modal
      v-model:visible="visible"
      :title="dialogTitle"
      :on-before-ok="handleSubmit"
      :onBeforeClose="handleBeforeClose"
      unmountOnClose
    >
      <a-form :model="algorithmForm" ref="algorithmFormRef" auto-label-width>
        <a-form-item
          field="algorithmName"
          label="算法名称"
          :rules="[{ required: true, message: '请填写算法名称' }]"
          :validate-trigger="['change', 'input']"
        >
          <a-input v-model="algorithmForm.algorithmName" placeholder="算法名称" />
        </a-form-item>
        <a-form-item field="algorithmCode" label="算法code">
          <a-input v-model="algorithmForm.algorithmCode" placeholder="算法code" />
        </a-form-item>
        <a-form-item field="algorithmType" label="算法类型">
          <a-select v-model="algorithmForm.algorithmType" placeholder="请选择算法类型" allow-clear>
            <a-option :value="item.code" v-for="item in algorithmTypeEnum" :key="item.code">{{ item.label }}</a-option>
          </a-select>
        </a-form-item>
        <a-form-item
          v-if="dialogType === 'add'"
          field="algorithmFileName"
          label="算法文件"
          :rules="[{ required: true, message: '请上传算法文件' }]"
        >
          <a-upload
            :limit="1"
            :custom-request="handleUpload"
            :show-file-list="true"
            :fileList="file"
            accept=".py"
            @before-remove="beforeRemove"
            :show-cancel-button="false"
            :show-retry-button="false"
          />
        </a-form-item>
        <a-form-item v-else field="algorithmFileName" label="算法文件">
          <a-input v-model="algorithmForm.algorithmFileName" disabled placeholder="算法文件" />
        </a-form-item>
        <a-form-item field="startServiceFile" label="算法服务启动文件名">
          <a-input v-model="algorithmForm.startServiceFile" placeholder="算法服务启动文件名" />
        </a-form-item>
        <a-form-item field="trialAddr" label="模型训练地址">
          <a-input v-model="algorithmForm.trialAddr" placeholder="模型训练地址" />
        </a-form-item>
        <a-form-item field="predictAddr" label="模型调用地址">
          <a-input v-model="algorithmForm.predictAddr" placeholder="模型调用地址" />
        </a-form-item>
        <a-form-item field="algorithmDesc" label="算法描述">
          <a-textarea v-model="algorithmForm.algorithmDesc" placeholder="请输入算法描述" allow-clear />
        </a-form-item>
      </a-form>
    </a-modal>
    <a-modal v-model:visible="detailVisible" title="算法详情" ok-text="关闭" hide-cancel>
      <a-descriptions :data="descData" bordered size="large" :column="1" />
    </a-modal>
  </div>
</template>

<style scoped lang="less">
.page-algorithm-management {
  height: 100%;

  .table-card {
    height: 100%;

    &-header {
      margin-bottom: 16px;
      &-right {
        text-align: right;
      }
    }

    &-footer {
      margin-top: 16px;
      margin-right: 16px;
      display: flex;
      justify-content: flex-end;
    }
  }
}
</style>
